home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Tele / Pete Johnson / HelloTabby.p Folder / HelloTabby.p < prev   
Encoding:
Text File  |  1991-06-23  |  12.6 KB  |  369 lines  |  [TEXT/PJMM]

  1. unit HelloTabby;
  2.  
  3. {     Written by Pete Johnson                                            }
  4. {    Version 1.0 of June 22, 1991 -- first version number assigned            }
  5.  
  6. { Source for a Think Pascal unit which handles the Tabby launch.next file,        }
  7. { returns the name of the next application to launch in a variable called        }
  8. { NextLaunch and allows MultiFinder some cycles if the Tabby Setup file says    }
  9. { Multifinder is running.                                            }
  10.  
  11. {            ********** History **********                                }
  12.  
  13. { Modified Mar. 11, 1989, to handle up to 100 events of < 32 chars apiece.        }
  14. { Modified Apr. 17 and May 6, 1989, to handle MultiFinder.                    }
  15. { Modified June 11, 1989, to use Toolbox file calls.                        }
  16. { Modified June 15, 1989, to use Tabby Setup name for 'BBS' string.            }
  17. { Modified July 22, 1989, for additional error checking.                    }
  18. { Modified Nov. 19, 1989, to incorporate WaitNextEvent delay for MultiFinder    }
  19. { Modified Jan. 20, 1990, to include all variable declarations necessary --    }
  20. {                        this unit uses no external globals.            }
  21. { Modified Mar. 03, 1990, to use Tabby Setup file rather than Config file for    }
  22. {                        info re: MF, BBSName etc. This allows Mansion    }
  23. {                        compatibility.                                }
  24. { Modified June 16, 1991, to record default path and some other subtle changes.    }
  25. { Modified June 22, 1991, to make backup of launch.next file in case of error.    }
  26.  
  27. { This source code is being made public in the hopes that it will lead to more    }
  28. { and better Tabby applications. I ask only that you credit me with a thanks    }
  29. { if you incorporate any or all of this code in an application. If you improve    }
  30. { on this code, please share your ideas.                                }
  31.  
  32. { If you're not using Think Pascal, you're on your own. I'm sure someone        }
  33. { other than me can help you if you need to convert this code for Turbo, TML    }
  34. { or Apple's MPW Pascal.                                                }
  35.  
  36. { Thanks to Erik Selberg, who has been a real help.                        }
  37.  
  38. { How to use this code:                                                }
  39.  
  40. {  <1> Create a Think Pascal Project                                    }
  41. {  <2> Add the HelloTabby.p file as the first unit                        }
  42. {  <3> Create your own additional files                                    }
  43.  
  44. { You should include an STR  resource 500 in the Project: this holds the name    }
  45. { of the default launch.next application (usually the BBS application).        }
  46.  
  47. {   Your main program Unit should include the following lines at its start:    }
  48.  
  49. {     uses                                                        }
  50. {       HelloTabby;                                                    }
  51.  
  52. {   Begin the main procedure of your program as follows:                    }
  53.  
  54. {    HelloTabby;                                                    }
  55.  
  56. {   End the main procedure of your program as follows:                        }
  57.  
  58. {    if NextLaunch <> '' then                                            }
  59. {       LaunchNextAppl                                                }
  60. {    end.                                                            }
  61.  
  62. {    The following global variables are available to your program:            }
  63.  
  64. {    NextLaunch: STR255;        --    Name of next app to launch, empty if none.    }
  65. {    MultiFinder : boolean;    --    True if Tabby Config says MF, else false.    }
  66. {    Err: OSErr;            --    General variable you can use for OSErrs.    }
  67. {    vRefNum: integer;        --    Reference number of default volume.        }
  68. {    dirID: longint;        --    Reference number of default directory.        }
  69. {    gDefaultpath: str255    --    Full path to default dir (ends w/colon).    }
  70. {    gVolName: STR255;        --    Name of default volume.                    }
  71. {    BBSName: STR255;        --    Name of BBS application                    }
  72. {    BaudString: STR255;        --    Baud rate from Tabby Setup in ASCII        }
  73. {    PortString: STR255;        --    'a' = modem, 'b' = printer                }
  74.  
  75. interface
  76.  
  77.     type
  78.         pLaunchStruct = ^LaunchStruct;
  79.         LaunchStruct = record
  80.                 pfName: StringPtr;
  81.                 param: INTEGER;
  82.                 LC: packed array[0..1] of CHAR;    {    extended parameters:                    }
  83.                 extBlockLen: LONGINT;             {    number of bytes in extension = 6            }
  84.                 fFlags: INTEGER;                    {    Finder file info flags                    }
  85.                 launchFlags: LONGINT;             {    bit 31,30=1 for sublaunch, others reserved    }
  86.             end;                             {    LaunchStruct                            }
  87.  
  88.     const
  89.         sleep = 10;
  90.  
  91.     var
  92.         NextLaunch, gVolName, BBSName, BaudString, PortString, gDefaultpath: STR255;
  93.         MultiFinder: boolean;
  94.         Err: OSErr;
  95.         vRefNum: integer;
  96.         dirID: longint;
  97.         IgnoreBool: boolean;                {    These variables for WaitNextEvent calls    }
  98.         TabbyEventRec: EventRecord;
  99.  
  100.     function PathNameFromDirID (DirID: longint; vRefNum: integer): str255;
  101.  
  102.     procedure LaunchNextAppl;
  103.  
  104.     procedure HelloTabby;
  105.  
  106.     procedure ReadTabbyConfig;
  107.  
  108.     function ReadALine (FileRefNum: integer; var TheMessage: string): OSErr;    {very useful!}
  109.  
  110. implementation
  111.  
  112. {-----------------------------------------------------------------    }
  113.  
  114.     function ReadALine;        {    (FileRefNum: integer; var TheMessage: string): OSErr;    }
  115.  
  116.         var
  117.             myPB: ParamBlockRec;
  118.             myString: Str255;
  119.  
  120.     begin
  121.         myString := '';
  122.         myPB.ioCompletion := nil;
  123.         myPB.ioRefNum := FileRefNum;
  124.         myPB.ioBuffer := Pointer(@myString[1]);
  125.         myPB.ioReqCount := 255;
  126.         myPB.ioPosMode := 3456; {ASCII 13*256+128}
  127.         myPB.ioPosOffset := 0; {ignored}
  128.         ReadALine := PBRead(@myPB, False);
  129.         if (myString[myPB.ioActCount] = chr(13)) then
  130.             myString[0] := char(myPB.ioActCount - 1) {Drop CR}
  131.         else
  132.             myString[0] := char(myPB.ioActCount);
  133.         TheMessage := myString
  134.     end;
  135.  
  136. {-----------------------------------------------------------------    }
  137.  
  138.     procedure ReadTabbyConfig;
  139.  
  140.         var
  141.             ConfigRefNum, MFCount: integer;
  142.             OneLine: str255;
  143.  
  144.     begin
  145.         Err := FSOpen(concat(gDefaultpath, 'Tabby:Tabby Setup'), vRefNum, ConfigRefNum);
  146.         if Err = noErr then
  147.             begin
  148.                 Err := ReadALine(ConfigRefNum, BBSName);    {    Name of BBS application        }
  149.                 Err := ReadALine(ConfigRefNum, OneLine);    {    MF status: 1 true, 0 false    }
  150.                 if OneLine[1] = '1' then
  151.                     begin
  152.                         MultiFinder := true;
  153.     {    We now have a valid boolean value for MultiFinder, so let's yield time if appropriate.    }
  154.     {    10 ticks (1/6 sec) times 20 = 3.2 seconds -- same value Michael Connick uses.            }
  155.                         for MFCount := 1 to 20 do
  156.                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil)
  157.                     end
  158.                 else
  159.                     MultiFinder := false;
  160.                 Err := ReadALine(ConfigRefNum, BaudString);    {    Baud rate in ASCII            }
  161.                 Err := ReadALine(ConfigRefNum, PortString)    {    'a' = modem, 'b' = printer    }
  162.             end;        {    if Err = noErr    }
  163.         Err := FSClose(ConfigRefNum)
  164.     end;
  165.  
  166. { ------------------------------------------------------ }
  167.  
  168.     function Launchit (pLnch: pLaunchStruct): OSErr;
  169.  
  170.     inline
  171.         $205F, $A9F2, $3E80;
  172.  
  173. { ------------------------------------------------------ }
  174.  
  175.     procedure LaunchNextAppl;
  176.  
  177.         var
  178.             pMyLaunch: pLaunchStruct;
  179.             myLaunch: LaunchStruct;
  180.             MyPB: CInfoPBRec;
  181.             MFCount: integer;
  182.  
  183.     begin
  184.  
  185.         with MyPB do
  186.             begin
  187.                 ioNamePtr := @NextLaunch;
  188.                 ioVRefNum := vRefNum;
  189.                 ioFDirIndex := 0;
  190.                 ioDirID := 0;
  191.             end;    {    with    }
  192.         Err := PBGetCatInfo(@MyPB, false);
  193.  
  194.         pMyLaunch := @myLaunch;
  195.         with pMyLaunch^ do
  196.             begin
  197.                 pfName := @NextLaunch;
  198.                 param := 0;
  199.                 LC[0] := 'L';
  200.                 LC[1] := 'C';
  201.                 extBlockLen := 6;
  202.                 fFlags := myPB.ioFlFndrInfo.fdFlags;
  203.                 if MultiFinder then
  204.                     LaunchFlags := $C0000000            {    set BOTH high bits for a sublaunch        }
  205.                 else
  206.                     LaunchFlags := $00000000;        {    just launch, then quit                }
  207.             end;                            {    with pMyLaunch^                    }
  208.         if MultiFinder then
  209.             for MFCount := 1 to 20 do
  210.                 IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);    {    Give away more cycles    }
  211.         Err := Launchit(pMyLaunch)
  212.     end;
  213.  
  214. { ------------------------------------------------------ }
  215.  
  216.     function PathNameFromDirID;{ (DirID: longint; vRefNum: integer): str255}
  217.  
  218.         var
  219.             Block: CInfoPBRec;
  220.             directoryName, FullPathName: str255;
  221.  
  222.     begin
  223.         FullPathName := '';
  224.         with Block do
  225.             begin
  226.                 ioNamePtr := @directoryName;
  227.                 ioDrParID := DirID
  228.             end;
  229.  
  230.         repeat
  231.             with Block do
  232.                 begin
  233.                     ioVRefNum := vRefNum;
  234.                     ioFDirIndex := -1;
  235.                     ioDrDirID := Block.ioDrParID
  236.                 end;
  237.             err := PBGetCatInfo(@Block, FALSE);
  238.  
  239.             directoryName := concat(directoryName, ':');
  240.             FullPathName := concat(directoryName, FullPathName)
  241.         until (Block.ioDrDirID = fsRtDirID);
  242.  
  243.         PathNameFromDirID := FullPathName
  244.     end;
  245.  
  246. { ------------------------------------------------------ }
  247.  
  248.     procedure HelloTabby;
  249.  
  250. { This procedure looks for a Tabby launch.next file. If it's found, it         }
  251. { extracts the events, which are comma delimited, saves the first one            }
  252. { for the next launch and rewrites the file from event #2 to the last            }
  253. { event.                                                            }
  254.  
  255. { If it finds only one event, it kills the launch.next file.                   }
  256.  
  257. { If there are no events, it returns the application name contained in        }
  258. { STR  500 as STR255 NextLaunch, otherwise it uses NextLaunch to hold          }
  259. { the first entry in the launch.next script.                                 }
  260.  
  261. { Before returning, it also checks that the NextLaunch application exists        }
  262. { by trying to    open it. If the open attempt fails, it returns NextLaunch        }
  263. { as an empty string.                                                }
  264.  
  265.         type
  266.             HundredEvents = array[1..100] of string[32];
  267.             ManyChars = packed array[1..3300] of char;    {    Can hold 100 32-length events, commas and one <CR>    }
  268.  
  269.         var
  270.             EventCounter, EventLimit, LNRefNum, LaunchCount: integer;
  271.             LNChar: char;
  272.             TheChars: ManyChars;
  273.             Event: HundredEvents;
  274.             Events, ThisEvent, TempString, BBSName: STR255;
  275.             logicalEOF, Quantity, CharIndex: longint;
  276.             CharCount, SetUpRef, SetUpCount: integer;
  277.             fndrInfo: FInfo;
  278.  
  279.     begin
  280.         SetCursor(GetCursor(WatchCursor)^^);
  281.         Err := HGetVol(@gVolName, vRefNum, dirID);        { Get volume ref # & dirID for default volume    }
  282.         gDefaultpath := PathNameFromDirID(dirID, vRefNum);    { Get full pathname                            }
  283.         Events := '';
  284.         for EventCounter := 1 to 100 do
  285.             Event[EventCounter] := '';
  286.         ThisEvent := '';
  287.         LNChar := chr(255);                    {    Dummy value so we can spot this first time through    }
  288.         NextLaunch := GetString(500)^^;        {    Get next launch string from resource                }
  289.         ReadTabbyConfig;                    {    See if we're running MultiFinder & yield time if so    }
  290.         EventCounter := 1;
  291.         Err := FSOpen(concat(gDefaultpath, 'launch.next'), vRefNum, LNRefNum);
  292.         Err := GetEOF(LNRefNum, logicalEOF);
  293.         if (logicalEOF > 0) and (Err = NoErr) then
  294.             begin
  295.                 Err := SetFPos(LNRefNum, fsFromStart, 0);
  296.                 LaunchCount := 0;
  297.                 while (LNChar <> chr(13)) & (LaunchCount <= logicalEOF) do
  298.                     begin
  299.                         if MultiFinder then
  300.                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  301.                         while (LNChar <> ',') & (LNChar <> chr(13)) & (LaunchCount <= logicalEOF) do
  302.                             begin
  303.                                 if (LNChar <> chr(255)) then
  304.                                     ThisEvent := concat(ThisEvent, LNChar);
  305.                                 LaunchCount := LaunchCount + 1;
  306.                                 Quantity := 1;
  307.                                 Err := FSRead(LNRefNum, Quantity, @LNChar);
  308.                                 LNChar := chr(ord(LNChar) div 256);
  309.                             end;            { (LNChar <> ',') & (LNChar <> chr(13)) & (LaunchCount <= logicalEOF) }
  310.                         Event[EventCounter] := ThisEvent;
  311.                         EventCounter := EventCounter + 1;
  312.                         ThisEvent := '';
  313.                         LNChar := chr(255)
  314.                     end;            { (LNChar <> chr(13)) & (LaunchCount <= logicalEOF) }
  315.                 Err := FSClose(LNRefNum);
  316.                 Err := FSDelete(concat(gDefaultpath, 'launch.next'), vRefNum);
  317.                 EventLimit := (EventCounter - 2);
  318.                 if EventLimit > 1 then
  319.                     begin
  320.                         Err := Create(concat(gDefaultpath, 'launch.next'), vRefNum, 'QED1', 'TEXT');
  321.                         Err := FSOpen(concat(gDefaultpath, 'launch.next'), vRefNum, LNRefNum);
  322.                         Err := SetFPos(LNRefNum, fsFromStart, 0);
  323.                         CharIndex := 0;
  324.                         for EventCounter := 2 to EventLimit do
  325.                             begin
  326.                                 if MultiFinder then
  327.                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  328.                                 TempString := Event[EventCounter];
  329.                                 for CharCount := 1 to length(TempString) do
  330.                                     TheChars[CharIndex + CharCount] := TempString[CharCount];
  331.                                 CharIndex := CharIndex + length(TempString) + 1;
  332.                                 if EventCounter <> EventLimit then
  333.                                     TheChars[CharIndex] := ','
  334.                                 else
  335.                                     TheChars[CharIndex] := chr(13);
  336.                             end; {Counter loop}
  337.                         Err := FSWrite(LNRefNum, CharIndex, @TheChars);
  338.                         Err := FSClose(LNRefNum);
  339.                         Err := FlushVol(@gVolName, vRefNum);
  340.                     end; {EventLimit > 1}
  341.                 if EventLimit > 0 then
  342.                     NextLaunch := Event[1];
  343.                 TempString := NextLaunch;
  344.                 UprString(TempString, false);
  345.                 if TempString = 'BBS' then
  346.                     begin
  347.                         Err := FSOpen(concat(gDefaultpath, 'Tabby:Tabby Setup'), vRefNum, SetupRef);
  348.                         if Err = NoErr then
  349.                             Err := GetEOF(SetupRef, logicalEOF);
  350.                         if (logicalEOF > 0) & (Err = NoErr) then
  351.                             begin
  352.                                 Err := ReadALine(LNRefNum, NextLaunch);
  353.                                 Err := FSClose(SetupRef);
  354.                             end        {    if logicalEOF > 0 for 'Tabby Setup'    }
  355.                     end;        {    if TempString = 'BBS'     }
  356.             end        {    if logicalEOF > 0 for 'launch.next'    }
  357.         else
  358.             begin
  359.                 Err := FSClose(LNRefNum);
  360.                 Err := FSDelete(concat(gDefaultpath, 'launch.next.bak'), vRefNum);
  361.                 Err := Rename(concat(gDefaultpath, 'launch.next'), vRefNum, concat(gDefaultpath, 'launch.next.bak'))
  362.             end;
  363.         Err := GetFInfo(NextLaunch, vRefNum, fndrInfo);    {    Is it an application?    }
  364.         if (Err <> noErr) | (fndrInfo.fdType <> 'APPL') then
  365.             NextLaunch := '';
  366.         if MultiFinder then
  367.             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil)
  368.     end;            { HelloTabby procedure }
  369. end.                { Unit }